
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jpsearch.JPSearchMetadataHandler;
import jpsearch.JPSearchParser;
import jpsearch.JPSearchRewriter;
import jpsearch.JPSearchTranslator;
import jpsearchcore.JPSearchCore;

import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.apache.sanselan.formats.tiff.constants.ExifTagConstants;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.constants.TiffFieldTypeConstants;
import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory;
import org.apache.sanselan.formats.tiff.write.TiffOutputField;
import org.apache.sanselan.formats.tiff.write.TiffOutputSet;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws ImageReadException, ImageWriteException {

		String xml = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
				"<ImageDescription xmlns=\"JPSearch:schema:coremetadata\" " + 
				"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
				"xsi:schemaLocation=\"urn:jpeg:jpsearch:schema:coremetadata:2009 24800-2-core.xsd\" >\n" +				
				"<Identifier></Identifier>\n " +
				"<GPSPositioning latitude=\"0\" longitude=\"0\" altitude=\"0\"/>\n" +
				"<RegionOfInterest>\n" +
				"<RegionLocator>\n" +
				"<Region dim=\"2\">777 290 777 350</Region>\n" +
				"</RegionLocator>\n" +
				"<Description>Ivan Ivanov</Description>\n" +
				"<Keyword></Keyword>\n" +
				"</RegionOfInterest>\n" + 
				"</ImageDescription>");

		//Un/Marshal metadata from String
		/*JPSearchCore jpsC = JPSearchMetadataHandler.unmarshal(xml);
		if(JPSearchMetadataHandler.marshal(jpsC, new File("test.xml")))
			System.out.println("WRITE OK");*/

		//Un/Marshal metadata from file	
		/*	JPSearchCore jpsC = JPSearchMetadataHandler.unmarshal(new File("file.xml"));
		if(JPSearchMetadataHandler.marshal(jpsC, new File("test.xml")))
			System.out.println("WRITE OK");*/

		//jpsC.dumpData();

		//Change native metadata
		/*	File file = new File("test.jpg"); //Change filename here
		File dst = new File("OutputImage.jpg");		
		changeMetadata(file, dst);
		System.out.println("DONE");*/

		//Test JPSearchRewriter and Parser
		/*try {
			new JPSearchRewriter().testUpdateJPSearchData();
			new JPSearchParser("Output.jpg").testReadJPSearchData();

		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("Metadata changed correctly\n");
		 */
		//Manually alter JPSearch metadata (XML)
		/*JPSearchParser testImage = new JPSearchParser("Output.jpg");
		JPSearchCore jpsC = JPSearchMetadataHandler.unmarshal(testImage.getXmlMetadata());
		jpsC.dumpData();

		{
			//Manually change creators
			List<Person> newCreators = new ArrayList<Person>();
			newCreators.add(new Person("Nicolas", "Demetriou"));
			newCreators.add(new Person("Herman", "Toothroot"));
			jpsC.setCreators(newCreators);

		}

		String newXML = JPSearchMetadataHandler.marshal(jpsC);
		 */

		//import example_4_2_4.xml to Output2.jpg file
		File output = new File("Output2.jpg");
		try {
			JPSearchCore jpsC = JPSearchMetadataHandler.unmarshal(new File("example_4_2_4.xml"));
			String newXML = JPSearchMetadataHandler.marshal(jpsC);
			new JPSearchRewriter().updateJPSearchData(new File("Output.jpg"), output, newXML);
			System.out.println(new JPSearchParser("Output2.jpg").getXmlMetadata());
		} catch (IOException e) {
			e.printStackTrace();
		}	

		//new exifSegment(new File("test.jpg"));

		/*JPSearchCore jpsC = JPSearchTranslator.translateToJPSCore(new File("deviantArt_example.xml"), new File("deviantartRules.xml"));
		JPSearchMetadataHandler.marshal(jpsC, new File("Output.xml"));
		System.out.println("Success");*/

		//createEmptyXMLRules(new File("core_structure.txt"), new File("test_rules.xml"));
		/*Map<String, String> unknownElements = new HashMap<String, String>();
		JPSearchCore jpsC = JPSearchTranslator.translateToJPSCore(new File("test_intance.xml"), new File("test_rules.xml"), unknownElements);
		JPSearchMetadataHandler.marshal(jpsC, new File("Output.xml"));
		System.out.println("Success! \nUnknown Elements: " + unknownElements);*/
	}

	public static void createEmptyXMLRules(File structure, File output){
		
		String xmlHeader = new String("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
		String header = new String("<TranslationRules xmlns=\"JPSearch:schema:translation " +
				"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance " +
				"xsi:schemaLocation=\"JPSearch:schema:translation 24800-2-translation.xsd\"" +
				"fromFormat=\"JPSearch:schema:coremetadata\" toFormat=\"urn:mpeg:mpeg7:schema:2004\">\n");

		String footer = new String("</TranslationRules>");

		String starting = new String("\t<TranslationRule xsi:type=\"OneToOneFieldTranslationType\">\n" +
				"\t\t<FromField xsi:type=\"SourceFieldType\">\n" +         
				"\t\t\t<XPathExpression>");

		String following = new String("</XPathExpression>\n" +    
				"\t\t</FromField>\n" + 
				"\t\t<ToField xsi:type=\"TargetFieldType\">\n" +
				"\t\t\t<XPathExpression>");

		String closing = new String("</XPathExpression>\n"+
				"\t\t</ToField>\n" +
				"\t</TranslationRule>\n");

		BufferedWriter bw = null;
		BufferedWriter bw2 = null;
		BufferedReader br = null;

		try {

			//Initialize output file
			if (!output.exists()) {
				output.createNewFile();
			}
			FileWriter fw = new FileWriter(output.getAbsoluteFile());
			bw = new BufferedWriter(fw);

			//write header
			bw.write(xmlHeader);
			bw.write(header);

			//Read structure file
			br = new BufferedReader(new FileReader(structure));

			String sCurrentLine;
			List<String> tags = new ArrayList<String>();

			while ((sCurrentLine = br.readLine()) != null) {
				if(!sCurrentLine.equals("")){
					String line [] = sCurrentLine.split(" ");
					bw.write(starting);
					
					if(line.length > 1 && !line[1].equals("")){
						bw.write(line[1]);
						tags.add(line[1]);
					}
					
					bw.write(following);
					bw.write(line[0]);
					bw.write(closing);
				}
			}

			bw.write(footer);
			System.out.println(output.getAbsolutePath() + " was created");
			
			//CREATE XML instance EXAMPLE
			FileWriter fw2 = new FileWriter(new File("test_intance.xml"));
			bw2 = new BufferedWriter(fw2);
			
			bw2.write(xmlHeader);
			bw2.write("<testexample>\n");
			
			for(String s : tags){
				bw2.write("\t<" + s + "></" + s + ">\n");
			}
			
			bw2.write("</testexample>");
			System.out.println("test_intance.xml was created");

		} catch (IOException e) {
			e.printStackTrace();
		}
		finally{
			try {
				bw.close();
				bw2.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void changeMetadata(File file, File output) {
		IImageMetadata metadata = null;
		JpegImageMetadata jpegMetadata = null;
		TiffImageMetadata exif = null;
		OutputStream os = null;
		TiffOutputSet outputSet = new TiffOutputSet();

		// establish metadata
		try {
			metadata = Sanselan.getMetadata(file);
		} catch (ImageReadException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// establish jpegMedatadata
		if (metadata != null) {
			jpegMetadata = (JpegImageMetadata) metadata;
		}

		// establish exif
		if (jpegMetadata != null) {
			exif = jpegMetadata.getExif();
		}

		// establish outputSet
		if (exif != null) {
			try {
				outputSet = exif.getOutputSet();
			} catch (ImageWriteException e) {
				e.printStackTrace();
			}
		}

		if (outputSet != null) {      
			/*
			 * 
			 * CAMERA MODEL CHANGE
			 * 
			 */
			// check if field already EXISTS - if so remove         
			TiffOutputField cameraModelPre = outputSet.findField(TiffConstants.EXIF_TAG_MODEL);
			if (cameraModelPre != null) {
				outputSet.removeField(TiffConstants.EXIF_TAG_MODEL);
			}         

			// add field 
			try {               

				String model = "Canon IXUS 115HS";
				TiffOutputField cameraModel = new TiffOutputField(
						ExifTagConstants.EXIF_TAG_MODEL, 
						TiffFieldTypeConstants.FIELD_TYPE_ASCII, 
						model.length(), 
						model.getBytes());
				TiffOutputDirectory exifDirectory = outputSet.getOrCreateRootDirectory(); //Since camera model is included in the Root directory
				//we use the appropriate function
				exifDirectory.add(cameraModel);
			} catch (ImageWriteException e) {

				e.printStackTrace();
			}

			/*
			 * 
			 * CAMERA MAKER CHANGE
			 * 
			 */

			TiffOutputField cameraMakerPre = outputSet.findField(TiffConstants.EXIF_TAG_MAKE);
			if (cameraMakerPre != null) {
				outputSet.removeField(TiffConstants.EXIF_TAG_MAKE);
			}         

			// add field 
			try {               

				String model = "HP";
				TiffOutputField cameraMaker = new TiffOutputField(
						ExifTagConstants.EXIF_TAG_MAKE, 
						TiffFieldTypeConstants.FIELD_TYPE_ASCII, 
						model.length(), 
						model.getBytes());
				TiffOutputDirectory exifDirectory = outputSet.getOrCreateRootDirectory(); //Since camera model is included in the Root directory
				//we use the appropriate function
				exifDirectory.add(cameraMaker);
			} catch (ImageWriteException e) {

				e.printStackTrace();
			}

			/*
			 * 
			 * XRESOLUTION CHANGE - Using different method          
			 *  
			 */

			TiffOutputField xresPre = outputSet.findField(TiffConstants.EXIF_TAG_XRESOLUTION);
			if (xresPre != null) {
				outputSet.removeField(TiffConstants.EXIF_TAG_XRESOLUTION);
			}         

			// add field 
			try {               

				TiffOutputField xres = TiffOutputField.create(
						ExifTagConstants.EXIF_TAG_XRESOLUTION, 
						outputSet.byteOrder, 
						new Double(74));

				TiffOutputDirectory exifDirectory = outputSet.getOrCreateRootDirectory(); //Since camera XRes is included in the Root directory
				//we use the appropriate function
				exifDirectory.add(xres);
			} catch (ImageWriteException e) {

				e.printStackTrace();
			}

			/*
			 * 
			 * DIGITAL ZOOM RATIO - Stored in EXIF directory
			 *  
			 */

			TiffOutputField zoomPre = outputSet.findField(TiffConstants.EXIF_TAG_DIGITAL_ZOOM_RATIO);
			if (zoomPre != null) {
				outputSet.removeField(TiffConstants.EXIF_TAG_DIGITAL_ZOOM_RATIO);
			}         

			// add field 
			try {               

				TiffOutputField zoom = TiffOutputField.create(
						TiffConstants.EXIF_TAG_DIGITAL_ZOOM_RATIO, 
						outputSet.byteOrder, 
						new Double(61146.071));

				TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory(); //Since camera XRes is included in the Root directory
				//we use the appropriate function
				exifDirectory.add(zoom);
			} catch (ImageWriteException e) {

				e.printStackTrace();
			}

			/*
			 * EXIF IMAGE WIDTH - Stored in EXIF directory
			 *  
			 */

			TiffOutputField imageWid = outputSet.findField(TiffConstants.EXIF_TAG_EXIF_IMAGE_WIDTH);
			if (imageWid != null) {
				outputSet.removeField(TiffConstants.EXIF_TAG_EXIF_IMAGE_WIDTH);
			}         

			// add field 
			try {               

				TiffOutputField xres = TiffOutputField.create(
						TiffConstants.EXIF_TAG_EXIF_IMAGE_WIDTH, 
						outputSet.byteOrder, 
						new Integer(2590));

				TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory(); //Since camera XRes is included in the Root directory
				//we use the appropriate function
				exifDirectory.add(xres);
			} catch (ImageWriteException e) {

				e.printStackTrace();
			}

		}       

		// create stream using temp file for dst
		try {
			os = new FileOutputStream(output);
			os = new BufferedOutputStream(os);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// write/update EXIF metadata to output stream
		try {
			new ExifRewriter().updateExifMetadataLossless(file, os, outputSet);
		} catch (ImageReadException e) {
			e.printStackTrace();
		} catch (ImageWriteException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
				}
			}
		} 
	}
}
